#include "mtest.h"
#include "mutil.h"

static void test_zero_length_array();
static void test_size_zero();
static void test_size_non_zero();
static void test_find();
static void test_endian_16();
static void test_endian_32();
static void test_endian_64();

char *zero_length_array[] = {
  NULL
};

char *non_zero_length_array[] = {
  "one",
  "two",
  "three",
  "four",
  "five"
};

uint8_t endianness_test[8] = {
  0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF
};

CU_TestInfo suite_cpp_find[] = {
  { "properly fail on a zero length array", test_zero_length_array },
  { "properly fail on a size of zero", test_size_zero },
  { "properly fail on a non zero size", test_size_non_zero },
  { "properly find an element", test_find },
  CU_TEST_INFO_NULL
};

CU_TestInfo suite_endian[] = {
  { "properly convert a 16 bit value with MU_HTON16 and MU_NTOH16", test_endian_16 },
  { "properly convert a 32 bit value with MU_HTON32 and MU_NTOH32", test_endian_32 },
  { "properly convert a 64 bit value with MU_HTON64 and MU_NTOH64", test_endian_64 },
  CU_TEST_INFO_NULL
};

CU_SuiteInfo mu_suites[] = {
  { "mu_cpp_find", NULL, NULL, suite_cpp_find },
  { "suite_endian", NULL, NULL, suite_endian },
  CU_SUITE_INFO_NULL
};

static void test_zero_length_array () {
  int rv;

  rv = mu_cpp_find( zero_length_array, "one", 0 );

  CU_ASSERT_EQUAL( rv, -1 );

}

static void test_size_zero() {
  int rv;

  rv = mu_cpp_find( non_zero_length_array, "one", 0 );

  CU_ASSERT_EQUAL( rv, -1 );
}

static void test_size_non_zero() {
  int rv;

  rv = mu_cpp_find( non_zero_length_array, "five", 3 );

  CU_ASSERT_EQUAL( rv, -1 );
}

static void test_find() {
  int rv;

  rv = mu_cpp_find( non_zero_length_array, "one", 5 );
  CU_ASSERT_EQUAL( rv, 0 );

  rv = mu_cpp_find( non_zero_length_array, "two", 5 );
  CU_ASSERT_EQUAL( rv, 1 );

  rv = mu_cpp_find( non_zero_length_array, "three", 5 );
  CU_ASSERT_EQUAL( rv, 2 );

  rv = mu_cpp_find( non_zero_length_array, "four", 5 );
  CU_ASSERT_EQUAL( rv, 3 );

  rv = mu_cpp_find( non_zero_length_array, "five", 5 );
  CU_ASSERT_EQUAL( rv, 4 );
}

static void test_endian_16() {
  uint16_t *p;
  uint16_t x;
  
  p = (uint16_t *) endianness_test;
  x = MU_HTON16( (uint16_t) *p);
  CU_ASSERT_EQUAL( (uint16_t) 0x0123, x );
  CU_ASSERT_EQUAL( (uint16_t) 0x0123, MU_HTON16( (uint16_t) *p ) );

  x = MU_NTOH16( (uint16_t) *p);
  CU_ASSERT_EQUAL( (uint16_t) 0x0123, x );
  CU_ASSERT_EQUAL( (uint16_t) 0x0123, MU_NTOH16( (uint16_t) *p ) );
}

static void test_endian_32() {
  uint32_t *p;
  uint32_t x;
  
  p = (uint32_t *) endianness_test;
  x = MU_HTON32( (uint32_t) *p);
  CU_ASSERT_EQUAL( (uint32_t) 0x01234567, x );
  CU_ASSERT_EQUAL( (uint32_t) 0x01234567, MU_HTON32( (uint32_t) *p ) );

  x = MU_NTOH32( (uint32_t) *p);
  CU_ASSERT_EQUAL( (uint32_t) 0x01234567, x );
  CU_ASSERT_EQUAL( (uint32_t) 0x01234567, MU_NTOH32( (uint32_t) *p ) );
}

static void test_endian_64() {
  uint64_t *p;
  uint64_t x;
  
  p = (uint64_t *) endianness_test;
  x = MU_HTON64( (uint64_t) *p);
  CU_ASSERT_EQUAL( (uint64_t) 0x0123456789ABCDEFLL, x );
  CU_ASSERT_EQUAL( (uint64_t) 0x0123456789ABCDEFLL, MU_HTON64( (uint64_t) *p ) );

  x = MU_NTOH64( (uint64_t) *p);
  CU_ASSERT_EQUAL( (uint64_t) 0x0123456789ABCDEFLL, x );
  CU_ASSERT_EQUAL( (uint64_t) 0x0123456789ABCDEFLL, MU_NTOH64( (uint64_t) *p ) );
}
